import { _decorator, Component, EventTouch, Material, Node, renderer, size, Size, Sprite, tween, Tween, UIOpacity, UITransform, v2, v3, v4, Vec2, Widget } from 'cc';
import EventManager from '../../Init/Managers/EventManager';
import { EventTypes } from '../../Init/Managers/EventTypes';
const { ccclass, property } = _decorator;
const tmpSize = size();
const tmpPos = v2();
/**
 * 控制mask显示区域和大小
 * 需要配合 spriteMask-2d-effect 使用
 */
@ccclass('SpriteMaskCmp')
export class SpriteMaskCmp extends Component {
    // 显示屏蔽层
    @property(Sprite)
    maskSprite: Sprite = null;
    // 触摸屏蔽层
    @property(Node)
    blockLayer: Node = null;

    maskOpacity: UIOpacity = null;

    //
    maskMat: Material = null;
    pass: renderer.Pass = null;
    paramName = 'maskSize';
    handle = 0;

    protected onLoad(): void {
        //
        this.maskMat = this.maskSprite.customMaterial;
        this.pass = this.maskMat.passes[0];
        this.handle = this.pass.getHandle(this.paramName);
        //
        this.maskOpacity = this.maskSprite.node.getComponent(UIOpacity);
        this.maskSprite.node.active = true;
        //
        this.loadMask();
    }

    onEvents() {
        // 事件监听
        EventManager.on(EventTypes.UIEvents.ShowSpriteMask, this.onShowSpriteMask, this);
        EventManager.on(EventTypes.UIEvents.HideSpriteMask, this.onHideSpriteMask, this);
    }
    offEvents() {
        // 事件监听
        EventManager.off(EventTypes.UIEvents.ShowSpriteMask, this.onShowSpriteMask, this);
        EventManager.off(EventTypes.UIEvents.HideSpriteMask, this.onHideSpriteMask, this);
    }


    protected onEnable(): void {
        this.onEvents();
        this.initMask();
        this.initOpacity();
    }
    protected onDisable(): void {
        this.offEvents();
        this.resetMask();
    }
    protected setEnable(isShow) {
        this.blockLayer.active = isShow;
    }

    protected update(dt: number) {
        this.updateMask(dt);
        this.updateOpacity(dt);
    }

    //#region -----监听外部事件-
    onShowSpriteMask(data: { size: Size, offset: Vec2, finishCb: Function, isAnim?: boolean, animTime?: number }) {
        this.showMask(data.size, data.offset, data.finishCb, data.isAnim, data.animTime);
        this.setOpacity(1);
    }
    onHideSpriteMask() {
        this.setEnable(false);
        this.setOpacity(0);
    }
    //#endregion

    //#region ---- 透明变化
    curOpacity = 0;
    toOpacity = 0; // 0-1

    initOpacity() {
        this.curOpacity = 1;
        this.toOpacity = 1;
        this.maskOpacity.opacity = 255;
    }
    // 0-1
    setOpacity(value: number, isAnim = true) {
        this.toOpacity = value;
        if (!isAnim) {
            this.curOpacity = value;
            this.maskOpacity.opacity = 255 * this.curOpacity;
        }
    }
    updateOpacity(dt) {
        let subO = this.toOpacity - this.curOpacity;
        if (subO != 0) {
            this.curOpacity += subO * 0.1;
            if (Math.abs(subO) < 0.01) {
                this.curOpacity = this.toOpacity;
            }
            this.maskOpacity.opacity = 255 * this.curOpacity;
        }

    }

    //#endregion

    //#region ---计算缩放比例

    // 屏幕尺寸
    _size: Size = size(0, 0);
    // xy 宽高比例 zw偏移比例
    maskParam = v4();
    // 记录mask显示区域
    maskSize = size();
    // 偏移中心点的坐标
    maskOffset = v2();
    //动画参数
    animTime = 0.5;
    toMaskParam = v4();
    isDirty = false;
    // 动画回调参数
    finishCb = null;
    // 触摸区域参数
    topBlockTrans: UITransform = null;
    btmBlockTrans: UITransform = null;
    leftBlockTrans: UITransform = null;
    rightBlockTrans: UITransform = null;
    // 显示触摸遮挡区域-方便调试
    isShowDebugger = false;

    private loadMask() {
        //
        this.topBlockTrans = this.blockLayer.getChildByName('top').getComponent(UITransform);
        this.btmBlockTrans = this.blockLayer.getChildByName('btm').getComponent(UITransform);
        this.leftBlockTrans = this.blockLayer.getChildByName('left').getComponent(UITransform);
        this.rightBlockTrans = this.blockLayer.getChildByName('right').getComponent(UITransform);
    }

    private initMask() {
        //
        this.setEnable(false);
        //
        this.blockLayer.getComponentsInChildren(Sprite).forEach(e => e.enabled = this.isShowDebugger);
        //
        let wg = this.node.getComponent(Widget);
        wg && (wg.updateAlignment());
        this._size.set(this.node.getComponent(UITransform).contentSize);
        this.maskParam.set(1, 1, 0, 0);
        this.toMaskParam.set(1, 1, 0, 0);
        this.isDirty = true;
        this.setUniform();
    }
    private resetMask() {
        Tween.stopAllByTarget(this.maskParam);
        // 注销事件
        this.setBlockTouchEvent(false);
    }
    // 是否监听block点击
    private setBlockTouchEvent(isListen: boolean) {
        for (let i = 0; i < this.blockLayer.children.length; i++) {
            const e = this.blockLayer.children[i];
            if (isListen) {
                e.on(Node.EventType.TOUCH_END, this.onBlockTouchEnd, this);
            } else {
                e.off(Node.EventType.TOUCH_END, this.onBlockTouchEnd, this);
            }
        }
    }

    // 监听触摸block-一次性监听
    private onBlockTouchEnd(event: EventTouch) {
        // 判断是否点击到block区域
        event.getUILocation(tmpPos);
        tmpPos.x -= this._size.width * 0.5;
        tmpPos.y -= this._size.height * 0.5;

        const _subX = Math.abs(tmpPos.x - this.maskOffset.x);
        const _subY = Math.abs(tmpPos.y - this.maskOffset.y);
        if (_subX > this.maskSize.width * 0.5 || _subY > this.maskSize.height * 0.5) {
            // 点击到block区域
            EventManager.emit(EventTypes.UIEvents.OnTouchSpriteMaskBlock, tmpPos);
            // 取消事件监听
            this.setBlockTouchEvent(false);
            console.log(' 点击到block区域');
        }

    }
    /** 设置mask wh宽高,zw偏移
     * @param size 大小
     * @param offset 整体偏移
     * @param finishCb mask开始动画完成时的回调
    */
    private showMask(size: Size, offset: Vec2, finishCb = null, isAnim: boolean = true, animTime = 0.5) {
        this.finishCb = finishCb;
        this.animTime = animTime;
        // 记录mask显示区域
        this.maskSize.set(size);
        this.maskOffset.set(offset);
        // 计算比例
        let _x = size.width * 0.5 / this._size.width;
        let _y = size.height * 0.5 / this._size.height;
        let _z = offset.x / this._size.width;
        let _w = offset.y / this._size.height;
        // 设置初始状态
        this.toMaskParam.set(_x, _y, _z, _w);
        // 开启显示
        this.setEnable(true);

        // 注销block触摸事件
        this.setBlockTouchEvent(false);
        // 设置初始block范围
        this.maskParam.set(0, 0, 0, 0);
        this.setBlockTouch();

        if (!isAnim) {
            this.maskParam.set(_x, _y, _z, _w);
            this.isDirty = true;
            this.setUniform();
            this.onAnimFinished();
        } else {
            this.showMaskAnim();
        }
    }
    /** 设置block区域范围 和 mask范围相反*/
    private setBlockTouch() {
        // 根据Mask显示比例 计算touch遮挡区域
        // top, btm
        this.topBlockTrans.setContentSize(this._size.width, this._size.height * (0.5 - this.maskParam.y - this.maskParam.w));
        this.btmBlockTrans.setContentSize(this._size.width, this._size.height * (0.5 - this.maskParam.y + this.maskParam.w));
        // left, right
        this.leftBlockTrans.setContentSize(this._size.width * (0.5 - this.maskParam.x + this.maskParam.z), this._size.height);
        this.rightBlockTrans.setContentSize(this._size.width * (0.5 - this.maskParam.x - this.maskParam.z), this._size.height);
    }

    private setUniform() {
        if (this.isDirty) {
            this.pass.setUniform(this.handle, this.maskParam);
        }
    }
    private updateMask(dt) {
        this.setUniform();
    }

    private showMaskAnim() {
        this.maskParam.set(1, 1, 0, 0);
        this.setUniform();

        this.isDirty = true;
        Tween.stopAllByTarget(this.maskParam);
        tween(this.maskParam).to(this.animTime, {
            x: this.toMaskParam.x, y: this.toMaskParam.y,
            z: this.toMaskParam.z, w: this.toMaskParam.w
        }, { easing: 'sineOut' }).
            call(() => {
                this.onAnimFinished();
            }).start();
    }
    private onAnimFinished() {
        this.finishCb && this.finishCb();
        this.finishCb = null;
        this.setBlockTouch();
        this.isDirty = false;
        // 注册事件
        this.setBlockTouchEvent(true);
    }

    //#endregion
}

